#include "SpotLight.h"

SpotLight::SpotLight(void)
{
	up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4.0f, 1.0f, 1.0f, 10000.0f);
	decay = 1.0f;
}

SpotLight::~SpotLight(void)
{
}

void SpotLight::updateLook()
{
	D3DXMatrixLookAtLH(&matView, &position, &target, &up);
}

void SpotLight::setPosition(const FLOAT x, const FLOAT y, const FLOAT z)
{
	position = D3DXVECTOR3(x, y, z);
	updateLook();
}

void SpotLight::setTarget(const FLOAT x, const FLOAT y, const FLOAT z)
{
	if (x == position.x && z == position.z) 
	{
		target = D3DXVECTOR3(x + D3DX_16F_EPSILON, y, z + D3DX_16F_EPSILON);
	} 
	else 
	{
		target = D3DXVECTOR3(x, y, z);
	}


	updateLook();
}

const D3DXMATRIX SpotLight::getViewMatrix()
{
	return matView;
}

const D3DXMATRIX SpotLight::getProjMatrix()
{
	return matProj;
}

const D3DXMATRIX SpotLight::getViewProjMatrix()
{
	return matView * matProj;
}

const D3DXMATRIX SpotLight::getWorldMatrix()
{
	D3DXVECTOR4 dir = getDirection4();

	D3DXVECTOR3 xy(dir.x, dir.y, dir.z);
	D3DXVECTOR3 xz(dir.x, 0.0f, 0.0f);
	D3DXVECTOR3 x(dir.x, 0.0, dir.z);
	
	FLOAT xLen = D3DXVec3Length(&x);
	FLOAT xyLen = D3DXVec3Length(&xy);
	FLOAT dotProduct = D3DXVec3Dot(&x, &xy);
	FLOAT zRot = acos(D3DXVec3Dot(&x, &xy) / (xLen * xyLen));

	if (dotProduct == 0 && dir.y > 0) {
		zRot = D3DX_PI/2.0f;
	} else  if (dotProduct == 0 && dir.y < 0) {
		zRot = D3DX_PI + D3DX_PI/2.0f;
	} else if (dir.y < 0) {
		zRot = (D3DX_PI * 2.0f) - zRot;
	} else if (dir.y == 0) {
		zRot = 0;
	}

	FLOAT xzLen = D3DXVec3Length(&xz);
	dotProduct = D3DXVec3Dot(&x, &xz);
	FLOAT yRot = acos(D3DXVec3Dot(&x, &xz) / (xLen * xzLen));

	if (dotProduct == 0 && dir.z > 0) {
		yRot = D3DX_PI/2.0f;
	} else if (dotProduct == 0 && dir.z < 0) {
		yRot = D3DX_PI + D3DX_PI/2.0f;
	} else if (dir.x < 0 && dir.z >= 0) {
		yRot = D3DX_PI - yRot;
	} else if (dir.x < 0 && dir.z < 0) {
		yRot = D3DX_PI + yRot;
	} else if (dir.x > 0 && dir.z < 0) {
		yRot = D3DX_PI * 2.0f - yRot;
	}

	D3DXMATRIX matWorld, matPos, matScale, matRotY, matRotZ;
	D3DXMatrixIdentity(&matWorld);

	D3DXMatrixTranslation(&matPos, position.x, position.y, position.z);

	D3DXMatrixScaling(&matScale, radius, radius, radius);

	D3DXMatrixRotationY(&matRotY, -yRot);
	D3DXMatrixRotationZ(&matRotZ, zRot);

	return matWorld * matRotZ * matRotY * matScale * matPos;
}

const D3DXVECTOR4 SpotLight::getDirection4()
{
	D3DXVECTOR3 direction;
	D3DXVec3Subtract(&direction, &target, &position);
	D3DXVec3Normalize(&direction, &direction);
	return D3DXVECTOR4(direction.x, direction.y, direction.z, 0.0f);
}
